/**
 * 
 */
package org.stars.daostars.loader.xml;

import java.io.File;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.stars.daostars.ParameterConverter;
import org.stars.daostars.core.Profile;
import org.stars.daostars.core.Source;
import org.stars.daostars.core.DaoStars;
import org.stars.database.ConnectionPoolManager;
import org.stars.util.diagnostic.StackTraceDiagnosticHandler;
import org.stars.util.StringUtility;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

/**
 * 
 * 
 * @author Francesco Benincasa (908099)
 * @date 06/nov/07, 20:21:56
 * 
 */
public class DaoStarsXmlLoader extends DefaultHandler {

	/**
	 * profilo corrente.
	 */
	private Profile currentProfile;
	
	private SAXParser parser;


	/**
	 * Costruttore. Inizializza il parser xml.
	 * @throws SAXException 
	 * @throws ParserConfigurationException 
	 */
	public DaoStarsXmlLoader() throws ParserConfigurationException, SAXException {
		parser=SAXParserFactory.newInstance().newSAXParser();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.xml.sax.helpers.DefaultHandler#endDocument()
	 */
	@Override
	public void endDocument() throws SAXException {

	}

	/**
	 * Logger
	 * 
	 * @return logger
	 */
	public Log getLog() {
		return LogFactory.getLog(getClass());
	}

	/**
	 * Carica il file xml che contiene la configurazione di base della libreria.
	 * Se va tutto bene restituisce 0. In caso di errore restituisce 1.
	 * 
	 * @param sFileName
	 *            nome completo del file di configurazione da caricare.
	 * @return numero di definizioni di dao trovate per il profilo attuale
	 * @throws Exception 
	 */
	public int loadFile(String sFileName) throws Exception {
		int ret = 0;
		Log log = getLog();
		try {
			File file=new File(sFileName);
			log.info("Daostars main configuration file "+file.getAbsoluteFile());
			parser.parse(file, this);
			Profile active = DaoStars.getInstance().getActiveProfile();

			if (active != null)
				ret = active.getSqlMapperSet().size();
			else
				ret = 0;
			
			log.debug("Daostars main configuration file loaded");
			
		} catch (Exception e) {
			// segnaliamo errore
			ret=1;
			log.error("There are problems to load file "+ e.getMessage());
			throw(e);
		}
		return ret;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String,
	 * java.lang.String, java.lang.String)
	 */
	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		Log log = getLog();

		if (Tag.PROFILE.equalsIgnoreCase(qName)) {
			// siamo all'interno del tag PROFILE
			if (currentProfile.getDaoSource().size() == 0) {
				log.debug("Profile " + currentProfile.getName().toUpperCase() + " does not contain source(s), so it will use the default source(s).");
				currentProfile.addSource(new Source());
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String,
	 * java.lang.String, java.lang.String, org.xml.sax.Attributes)
	 */
	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		Log log = getLog();
		DaoStars ds = DaoStars.getInstance();

		if (Tag.DAOSTARS.equalsIgnoreCase(qName)) {
			// siamo all'interno del tag DAOSTARS
		} else if (Tag.STACK_TRACE.equalsIgnoreCase(qName)) {
			// Siamo all'interno del tag STACKTRACE
			String stackClassHandler = StringUtility.nvl(attributes.getValue("class"), "").trim();

			String stackClassHandlerEnabled = StringUtility.nvl(attributes.getValue("enabled"), "true").trim();

			if (stackClassHandler.length() > 0) {
				// assert: stiamo cercando di definire uno stack handler diverso
				// da quello di default
				try {
					StackTraceDiagnosticHandler stackHandler = (StackTraceDiagnosticHandler) Class.forName(stackClassHandler).newInstance();
					currentProfile.setStackTraceDiagnosticHandler(stackHandler);
				} catch (Exception e) {
					log.error("It is impossibile to instanziate the stack handler " + stackClassHandler + ". Using the "
							+ currentProfile.getStackTraceDiagnosticHandler().getClass().getName() + " instead.");
				}
			}
			// abilitiamo o meno lo stack trace
			currentProfile.getStackTraceDiagnosticHandler().setEnabled("true".equalsIgnoreCase(stackClassHandlerEnabled) ? true : false);

		} else if (Tag.PARAM_CONVERTER.equalsIgnoreCase(qName)) {
			// Siamo all'interno del tag STACKTRACE
			String paramConverterClass = StringUtility.nvl(attributes.getValue("class"), "").trim();

			if (paramConverterClass.length() > 0) {
				// assert: stiamo cercando di definire uno stack handler diverso
				// da quello di default
				try {
					ParameterConverter paramConverter = (ParameterConverter) Class.forName(paramConverterClass).newInstance();
					currentProfile.setParameterConverter(paramConverter);
				} catch (Exception e) {
					log.error("It is impossibile to instanziate the parameters conversion handler " + paramConverterClass + ". Using the "
							+ currentProfile.getParameterConverter().getClass().getName() + " instead.");
				}
			}

		} else if (Tag.PROFILE.equalsIgnoreCase(qName)) {
			// Siamo all'interno del tag PROFILE
			currentProfile = new Profile();
			currentProfile.setName(StringUtility.nvl(attributes.getValue("name"), "default"));

			// impostiamo il connection pool di default
			String connection = StringUtility.nvl(attributes.getValue("connection")).trim();

			if (connection.length() == 0) {
				connection = ConnectionPoolManager.getInstance().getDefaultConnectionName();
			}
			currentProfile.setDefaultConnectionName(connection);

			ds.addProfile(currentProfile);
			log.debug("Found profile " + currentProfile.getName() + " with connection " + currentProfile.getDefaultConnectionName().toUpperCase());
		} else if (Tag.SRC.equalsIgnoreCase(qName)) {
			// Siamo all'interno del tag SRC
			Source source = new Source();

			// impostiamo le proprieta' del source
			String jar = StringUtility.nvl(attributes.getValue(TagAttribute.JAR), "").trim();
			String directory = StringUtility.nvl(attributes.getValue(TagAttribute.DIR), "/WEB-INF/daosql/").trim();
			String filePattern = StringUtility.nvl(attributes.getValue(TagAttribute.FILE), "*.xml").trim().toLowerCase();

			source.setJar(jar);
			source.setDirectory(directory);
			source.setFilePattern(filePattern);

			currentProfile.addSource(source);

			log.debug("For profile " + currentProfile.getName() + " found source jar=" + source.getJar() + " dir=" + source.getDirectory() + " file=" + source.getFilePattern());
		} else if (Tag.ACTIVE.equalsIgnoreCase(qName)) {
			// Siamo all'interno del tag ACTIVe

			String activeProfile = StringUtility.nvl(attributes.getValue("profile"), "default").trim();
			ds.setActiveProfile(activeProfile);

			if (ds.getActiveProfile() == null) {
				log.fatal("Can not use the profile as active profile  " + activeProfile.toUpperCase() + " because it does not exist!");
			}

		}
	}
}
